package com.anjubao.parking.municipal.parkinglot.service;

import com.anjubao.parking.municipal.common.exception.ServiceException;
import com.anjubao.parking.municipal.common.global.BusinessCodeEnum;
import com.anjubao.parking.municipal.common.utils.BeanUtils;
import com.anjubao.parking.municipal.common.utils.MunicipalParkingUtils;
import com.anjubao.parking.municipal.common.utils.U;
import com.anjubao.parking.municipal.parkinglot.constant.DeviceOperationStatusEnum;
import com.anjubao.parking.municipal.parkinglot.constant.DeviceStatusEnum;
import com.anjubao.parking.municipal.parkinglot.constant.DeviceTypeEnum;
import com.anjubao.parking.municipal.parkinglot.dto.ParkingLotDeviceChargingPileDto;
import com.anjubao.parking.municipal.parkinglot.dto.ParkingLotDto;
import com.anjubao.parking.municipal.parkinglot.dto.ParkingLotSlotDto;
import com.anjubao.parking.municipal.parkinglot.feign.ParkingLotFeignClient;
import com.anjubao.parking.municipal.parkinglot.form.ChargingPileQueryForm;
import com.anjubao.parking.municipal.parkinglot.form.ParkingLotDeviceChargingPileAddForm;
import com.anjubao.parking.municipal.parkinglot.mapper.ParkingLotDeviceChargingPileMapper;
import com.anjubao.parking.municipal.parkinglot.mapper.ParkingLotDeviceStatusMapper;
import com.anjubao.parking.municipal.parkinglot.model.ParkingLotDeviceChargingPile;
import com.anjubao.parking.municipal.parkinglot.model.ParkingLotDeviceStatus;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 
 * 充电桩服务
 * 
 * @author zhu.chunfeng
 *
 */
@Service
@Slf4j
public class ParkingLotDeviceChargingPileService{

    @Autowired
    private ParkingLotFeignClient parkingLotFeignClient;
    @Resource
    private ParkingLotDeviceChargingPileMapper parkingLotDeviceChargingPileMapper;
    @Resource
    private ParkingLotDeviceStatusMapper parkingLotDeviceStatusMapper;


    /**
     * 创建充电桩规则
     * @param form 表单参数
     * @return 数据库实体类
     */

    //TODO 机器码唯一性校验
    //TODO 充电桩/泊位一对一绑定校验
    public ParkingLotDeviceChargingPile createParkingLotDeviceChargingPileService(ParkingLotDeviceChargingPileAddForm form) {

        ParkingLotDeviceChargingPile parkingLotDeviceChargingPile = BeanUtils.transform(ParkingLotDeviceChargingPile.class, form);

        //生成ID和code
        parkingLotDeviceChargingPile.setId(U.id());
        parkingLotDeviceChargingPile.setCode(MunicipalParkingUtils.generateCode(parkingLotDeviceChargingPile.getId(), BusinessCodeEnum.PARKING_CHARGING_PILE_CODE.getCode()));

        //校验泊位编号
        String parkingLotSlotCode = form.getParkingLotSlotCode();
        //校验兼查询
        ParkingLotSlotDto parkingLotSlotDto = this.checkAndQueryParkingLotSlotCode(parkingLotSlotCode);
        parkingLotDeviceChargingPile.setParkingLotSlotId(MunicipalParkingUtils.getIdByCode(parkingLotSlotCode));
        parkingLotDeviceChargingPile.setParkingLotSlotName(parkingLotSlotDto.getName());

        //校验停车场信息
        String parkingLotCode = parkingLotSlotDto.getParkingLotCode(); //停车场编号
        ParkingLotDto parkingLotDto = this.checkAndQueryParkingLot(parkingLotCode);
        //冗余停车场字段
        this.copyParkingLotProperties(parkingLotDeviceChargingPile, parkingLotDto,parkingLotCode);

        //其余字段
        parkingLotDeviceChargingPile.setLastReportTime(LocalDateTime.now());

        parkingLotDeviceChargingPileMapper.insert(parkingLotDeviceChargingPile);

        ParkingLotDeviceStatus parkingLotDeviceStatus = this.convertChargingPileToDeviceStatus(parkingLotDeviceChargingPile,parkingLotDto);
        parkingLotDeviceStatus.setId(U.id());
        parkingLotDeviceStatus.setCode(MunicipalParkingUtils.generateCode(parkingLotDeviceStatus.getId(),BusinessCodeEnum.DEVICE_STATUS.getCode()));
        parkingLotDeviceStatusMapper.insert(parkingLotDeviceStatus);

        return parkingLotDeviceChargingPile;

    }

    /**
     * 由充电桩和停车场生成设备状态表
     * @param parkingLotDeviceChargingPile 充电桩
     * @param parkingLotDto 停车场
     * @return 设备状态表
     */
    private ParkingLotDeviceStatus convertChargingPileToDeviceStatus(ParkingLotDeviceChargingPile parkingLotDeviceChargingPile, ParkingLotDto parkingLotDto) {
        ParkingLotDeviceStatus parkingLotDeviceStatus = new ParkingLotDeviceStatus();
        parkingLotDeviceStatus.setDeviceId(parkingLotDeviceChargingPile.getId());
        parkingLotDeviceStatus.setDeviceCode(parkingLotDeviceChargingPile.getCode());
        parkingLotDeviceStatus.setDeviceName(parkingLotDeviceChargingPile.getName());
        parkingLotDeviceStatus.setDeviceType(DeviceTypeEnum.CHARGING_PILE.getCode());
        parkingLotDeviceStatus.setProvinceId(parkingLotDeviceChargingPile.getParkingLotProvinceId());
        parkingLotDeviceStatus.setProvinceName(parkingLotDeviceChargingPile.getParkingLotProvinceName());
        parkingLotDeviceStatus.setCityId(parkingLotDeviceChargingPile.getParkingLotCityId());
        parkingLotDeviceStatus.setCityName(parkingLotDeviceChargingPile.getParkingLotCityName());
        parkingLotDeviceStatus.setDistrictId(parkingLotDeviceChargingPile.getParkingLotDistrictId());
        parkingLotDeviceStatus.setDistrictName(parkingLotDeviceChargingPile.getParkingLotDistrictName());
        parkingLotDeviceStatus.setLocation(parkingLotDto.getLocation());
        parkingLotDeviceStatus.setNote(parkingLotDeviceChargingPile.getNote());
        parkingLotDeviceStatus.setFixBy(null);
        parkingLotDeviceStatus.setFixTime(null);
        parkingLotDeviceStatus.setFixNote(null);
        parkingLotDeviceStatus.setLastReportTime(LocalDateTime.now());
        parkingLotDeviceStatus.setIsOnline(DeviceOperationStatusEnum.OnLine.getCode());
        parkingLotDeviceStatus.setStatus(DeviceStatusEnum.Normal.getCode());
        return parkingLotDeviceStatus;
    }

    /**
     * 根据编号更新充电桩
     * @param parkingLotDeviceChargingPileCode 充电桩编号
     * @param form 更新字段
     */
    public void updateParkingLotDeviceChargingPile(String parkingLotDeviceChargingPileCode, ParkingLotDeviceChargingPileAddForm form) {

        ParkingLotDeviceChargingPile parkingLotDeviceChargingPile = BeanUtils.transform(ParkingLotDeviceChargingPile.class, form);
        long chargingPileId = MunicipalParkingUtils.getIdByCode(parkingLotDeviceChargingPileCode);
        parkingLotDeviceChargingPile.setId(chargingPileId);
        parkingLotDeviceChargingPile.setCode(parkingLotDeviceChargingPileCode);

        String parkingLotSlotCode = form.getParkingLotSlotCode();
        if (null != parkingLotSlotCode) {
            ParkingLotSlotDto parkingLotSlotDto = this.checkAndQueryParkingLotSlotCode(parkingLotSlotCode);
            parkingLotDeviceChargingPile.setParkingLotSlotName(parkingLotSlotDto.getName());
            parkingLotDeviceChargingPile.setParkingLotSlotId(MunicipalParkingUtils.getIdByCode(parkingLotSlotCode));

            //停车场信息
            ParkingLotDto parkingLotDto = this.checkAndQueryParkingLot(parkingLotSlotDto.getParkingLotCode());
            //冗余停车场字段
            this.copyParkingLotProperties(parkingLotDeviceChargingPile, parkingLotDto,parkingLotSlotDto.getParkingLotCode());
        }

        int effectiveRow = parkingLotDeviceChargingPileMapper.updateById(parkingLotDeviceChargingPile);
        if (effectiveRow == 0) {
            throw new ServiceException("编号为" + parkingLotDeviceChargingPileCode + "的充电桩记录不存在");
        }

        //更新状态表
        ParkingLotDeviceChargingPile chargingPile = parkingLotDeviceChargingPileMapper.selectById(chargingPileId);
        ParkingLotDeviceStatus parkingLotDeviceStatus = this.convertChargingPileToDeviceStatus(chargingPile, this.checkAndQueryParkingLot(chargingPile.getParkingLotCode()));
        UpdateWrapper<ParkingLotDeviceStatus> updateWrapper = new UpdateWrapper<>(new ParkingLotDeviceStatus().setDeviceId(chargingPileId));
        int update = parkingLotDeviceStatusMapper.update(parkingLotDeviceStatus, updateWrapper);
        if (update != 1) {
            throw new ServiceException("数据有误 请联系管理员 充电桩ID:" + chargingPileId);
        }


    }

    /**冗余停车场字段*/
    private void copyParkingLotProperties(ParkingLotDeviceChargingPile parkingLotDeviceChargingPile, ParkingLotDto dto,String parkingLotCode) {
        parkingLotDeviceChargingPile.setParkingLotId(MunicipalParkingUtils.getIdByCode(parkingLotCode));
        parkingLotDeviceChargingPile.setParkingLotCode(parkingLotCode);
        parkingLotDeviceChargingPile.setParkingLotName(dto.getName());
        parkingLotDeviceChargingPile.setParkingLotProvinceId(dto.getProvinceId());
        parkingLotDeviceChargingPile.setParkingLotProvinceName(dto.getProvinceName());
        parkingLotDeviceChargingPile.setParkingLotCityId(dto.getCityId());
        parkingLotDeviceChargingPile.setParkingLotCityName(dto.getCityName());
        parkingLotDeviceChargingPile.setParkingLotDistrictId(dto.getDistrictId());
        parkingLotDeviceChargingPile.setParkingLotDistrictName(dto.getDistrictName());
    }

    /**
     * 查询兼校验停车场信息
     * @param parkingLotCode 停车场code
     * @return 停车场实体类
     */
    private ParkingLotDto checkAndQueryParkingLot(String parkingLotCode) {
        ParkingLotDto dto = parkingLotFeignClient.getParkingLot(parkingLotCode).getResult();
        if (dto == null) {
            throw new ServiceException("找不到停车场");
        }
        return dto;
    }

    /**
     * 查询兼校验泊位
     * @param parkingLotSlotCode 泊位编号
     * @return 泊位编号实体类
     */
    private ParkingLotSlotDto checkAndQueryParkingLotSlotCode(String parkingLotSlotCode) {
        ParkingLotSlotDto parkingLotSlotDto = parkingLotFeignClient.getParkingLotSlotByCode(parkingLotSlotCode).getResult();
        if (parkingLotSlotDto == null) {
            throw new ServiceException("找不到泊位");
        }
        return parkingLotSlotDto;
    }


    /**
     * 通过code 查询充电桩详情
     * @param parkingLotDeviceChargingPileCode 充电桩 code
     * @return 详情
     */
    public ParkingLotDeviceChargingPileDto getParkingLotDeviceChargePile(String parkingLotDeviceChargingPileCode) {
        ParkingLotDeviceChargingPile parkingLotDeviceChargingPile = parkingLotDeviceChargingPileMapper.selectById(MunicipalParkingUtils.getIdByCode(parkingLotDeviceChargingPileCode));
        if (null == parkingLotDeviceChargingPile) {
            throw new ServiceException("找不到充电桩记录");
        }
        return this.convertChargingPileToDto(parkingLotDeviceChargingPile);
    }

    /**
     * 对象转换
     * 前端要求省市区去掉parkingLot前缀
     */
    private ParkingLotDeviceChargingPileDto convertChargingPileToDto(ParkingLotDeviceChargingPile parkingLotDeviceChargingPile) {
        ParkingLotDeviceChargingPileDto chargingPileDto = new ParkingLotDeviceChargingPileDto();
        BeanUtils.copyProperties(parkingLotDeviceChargingPile, chargingPileDto);
        //去掉parkingLot前缀
        chargingPileDto.setProvinceId(parkingLotDeviceChargingPile.getParkingLotProvinceId());
        chargingPileDto.setProvinceName(parkingLotDeviceChargingPile.getParkingLotProvinceName());
        chargingPileDto.setCityId(parkingLotDeviceChargingPile.getParkingLotCityId());
        chargingPileDto.setCityName(parkingLotDeviceChargingPile.getParkingLotCityName());
        chargingPileDto.setDistrictId(parkingLotDeviceChargingPile.getParkingLotDistrictId());
        chargingPileDto.setDistrictName(parkingLotDeviceChargingPile.getParkingLotDistrictName());
        return chargingPileDto;
    }

    /**
     * 通过编号 删除充电桩
     * @param parkingLotDeviceChargingPileCode 充电桩编号
     */
    public void deleteParkingLotDeviceChargePile(String parkingLotDeviceChargingPileCode) {
        //todo 数据关联校验
        long chargingPileId = MunicipalParkingUtils.getIdByCode(parkingLotDeviceChargingPileCode);
        int effectiveRow = parkingLotDeviceChargingPileMapper.deleteById(chargingPileId);
        if (effectiveRow == 0) {
            throw new ServiceException("找不到充电桩记录");
        }
        UpdateWrapper<ParkingLotDeviceStatus> updateWrapper = new UpdateWrapper<>(new ParkingLotDeviceStatus().setDeviceId(chargingPileId));
        int delete = parkingLotDeviceStatusMapper.delete(updateWrapper);
        if (delete != 1) {
            throw new ServiceException("数据有误 请联系管理员 code:"+parkingLotDeviceChargingPileCode);
        }
    }

    /**
     * 查询充电桩列表
     * @param query 查询条件
     * @param pageNum 页码
     * @param pageSize 页大小
     * @return page
     */
    public IPage<ParkingLotDeviceChargingPileDto> getParkingLotDeviceChargePilePages(ChargingPileQueryForm query, Integer pageNum, Integer pageSize) {


        IPage<ParkingLotDeviceChargingPile> page = new Page<>(pageNum, pageSize);
        QueryWrapper<ParkingLotDeviceChargingPile> queryWrapper = new QueryWrapper<>(new ParkingLotDeviceChargingPile()
                .setParkingLotProvinceId(query.getProvinceId())
                .setParkingLotCityId(query.getCityId())
                .setParkingLotDistrictId(query.getDistrictId())
        );
        queryWrapper.likeRight(StringUtils.isNotBlank(query.getMachineCode()), "machine_code", query.getMachineCode());
        queryWrapper.likeRight(StringUtils.isNotBlank(query.getName()), "name", query.getName());
        queryWrapper.likeRight(StringUtils.isNotBlank(query.getParkingLotSlotName()), "parking_lot_slot_name", query.getParkingLotSlotName());
        queryWrapper.likeRight(StringUtils.isNotBlank(query.getParkingLotName()), "parking_lot_name", query.getParkingLotName());

        IPage<ParkingLotDeviceChargingPile> deviceChargingPileIPage1 = parkingLotDeviceChargingPileMapper.selectPage(page, queryWrapper);
        return deviceChargingPileIPage1.convert(this::convertChargingPileToDto);
    }

    /**
     * 修改充电桩状态
     * @param parkingLotDeviceChargingPileCode 充电桩ID
     * @param isOnline 状态
     */
    public void updateIsOnline(String parkingLotDeviceChargingPileCode, Integer isOnline) {
        if (!DeviceOperationStatusEnum.exist(isOnline)) {
            throw new ServiceException("isOnline 枚举错误");
        }
        long id = MunicipalParkingUtils.getIdByCode(parkingLotDeviceChargingPileCode);
        ParkingLotDeviceChargingPile chargingPile = new ParkingLotDeviceChargingPile();
        chargingPile.setId(id);
        int effectiveRow = parkingLotDeviceChargingPileMapper.updateById(chargingPile);
        if (effectiveRow == 0) {
            throw new ServiceException("找不到充电桩");
        }
        //同步更新设备状态表
        UpdateWrapper<ParkingLotDeviceStatus> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("device_id", id);
        ParkingLotDeviceStatus entity = new ParkingLotDeviceStatus();
        entity.setIsOnline(isOnline);
        int update = parkingLotDeviceStatusMapper.update(entity, updateWrapper);
        if (update != 1) {
            throw new ServiceException("数据有误 请联系管理员 充电桩ID:" + id);
        }
    }

    /**
     * 根据车场code获取安装了充电桩的泊位id列表
     * @param parkingLotCode
     * @return
     */
    public List<Long> selectCharging(String parkingLotCode) {
        return parkingLotDeviceChargingPileMapper.selectCharging(parkingLotCode);
    }
}
